/*
 * FILE NAME: Grid.java
 * A Program to help User keep track of their working procedures as they embark on the OilSim simulation journey
 * More of an automated procedure where by a user is using this proposed software tool instead of pen and paper materials.
 */
package OilSimNoteBook;         // Package Declaration, it consists of classes, eg the class named Grid is located in this package.
/*
 * @authored by Abbey-Hart Reginald
 * @version Project Support tool 1.0
 * @start-date 17th June 2014
 * @end-date
 */

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;                       // contains farmiliar easy to use GUI components like buttons and text boxes amd also allows GUI to cross platform
import java.awt.*;                          // contains classes for creating user interface and used in performing drawing and painting operations
import java.awt.event.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

/*
 * Grid class extends JPanel,(simply means i am subclassing JPanel) and also the grid is the top level component that holds individual
 * cells as legend cells
 */
public class Grid extends OilSimUIComponent {

    public static final String INSTRUCTION_TXT = "* instrction 1\n"
            + "* instruction 2\n"
            + "* instruction 3\n";
    private static final long serialVersionUID = 1L;
    private GridCell[][] board;              // 2-Dim arrays used to create board of life cells
    private JButton labelGridButton;         // btn pressed for next generation
    private Integer startNumber = Integer.parseInt((JOptionPane.showInputDialog("Insert Starting Grid Number from Simulation", "Input Text Here")));
    //collects inputs from the Users for starting grid number for the simulation.
    private JTextField labelInput;           // text field created call labelInput   
    private JPanel gridPanel;                //Groups and repositions components being put on the JFrame

    private JPanel controlPanel, mainPanel;   // Another JPanel called contolPanel created
    private static final int rowCount = 14;  // rows and column intialized and made static
    private static final int columnCount = 14;
    private Map<JButton, Integer> buttonIdMap;

    public static int selectedLegend; //see *key variables that follow
    public static int magneticKey = 1;
    public static int gravimetricKey = 2;
    public static int environmentalKey = 3;
    public static int waterDepthKey = 4;

    public static String[] magneticOptions = {"Very Good", "Good", "Bad"};   // Takes in the following string options in the dialog box created
    public static String[] environmentalOptions = {"Good", "Bad"};           // Takes in the following string options in the dialog box created
    public static String[] gravimetricOptions = {"Very Good", "Good", "Bad"};// Takes in the following string options in the dialog box created

    public static Map<String, Color> magneticOptionsColors = new HashMap<String, Color>();
    public static Map<String, Color> gravimetricOptionsColors = new HashMap<String, Color>();
    public static Map<String, Color> environmentalOptionsColors = new HashMap<String, Color>();

    JLabel selectedButtonLabel;
    JLabel dummyLabel;

    public Grid() {
        magneticOptionsColors.put("Very Good", new Color(147, 112, 219));  // RGB Colour for purple to represent very good blocks.
        magneticOptionsColors.put("Good", new Color(255, 85, 163));        // RGB Colour for pink to represent very good blocks.
        magneticOptionsColors.put("Bad", new Color(255, 255, 190));        // RGB color for light yellow to represent bad magnetic blocks

        gravimetricOptionsColors.put("Very Good", Color.RED);  // No need for RGB colour it exists within Java Awt colour class
        gravimetricOptionsColors.put("Good", Color.YELLOW);    // No need for RGB colour it exists within Java Awt colour class
        gravimetricOptionsColors.put("Bad", new Color(202, 220, 255));    // RGB color for light Blue to represent bad gravimetric blocks   

        environmentalOptionsColors.put("Good", Color.GREEN);
        environmentalOptionsColors.put("Bad", new Color(204, 150, 150));

        gridPanel = new JPanel(new GridLayout(rowCount, columnCount));

        gridPanel.setBorder(new EmptyBorder(10, 10, 10, 10));

        controlPanel = new JPanel(new GridLayout(7, 2));

        buttonIdMap = new HashMap<JButton, Integer>();

        mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));

        JScrollPane scrollPane = new JScrollPane(gridPanel);

        // Identify horizontal scroll bar policy property and used [HORIZONTAL_SCROLLBAR_AS_NEEDED] to set horizontal scroll pane to only pop out when needed
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        // Identify vertical scroll bar policy property and used [VERTICAL_SCROLLBAR_AS_NEEDED] to set vertical scroll pane to only pop out when needed
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        //scrollPane.setMinimumSize(new Dimension(400, 200));

        board = new GridCell[rowCount][columnCount];
        int s = startNumber;
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                board[i][j] = new GridCell(board, i, j, s);
                s++;
            }
        }

        this.initBoard();

        /* This layout is made up of seven rows for each 
         * item as well as two columns. The two columns are needed to accommodate the 
         * row that has an input as well as a button. The remaining rows have single
         * items in each row so to compensate, a label control is included in each
         * row but this label has no content so is invisible and we have the 
         * visual arrangement that is needed.
         */
        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.PAGE_AXIS));
        controlPanel.setAlignmentY(JPanel.TOP_ALIGNMENT);

        selectedButtonLabel = new JLabel();
        dummyLabel = new JLabel();

        JButton magneticButton = new JButton(" Magnetic Info ");
        buttonIdMap.put(magneticButton, magneticKey);
        magneticButton.addActionListener(new AttrButtonClickListener());
        JLabel magneticButtonLabel = new JLabel();

        JButton gravimetricButton = new JButton(" Gravimetric Info ");
        buttonIdMap.put(gravimetricButton, gravimetricKey);
        gravimetricButton.addActionListener(new AttrButtonClickListener());
        JLabel gravimetricButtonLabel = new JLabel();

        JButton environmentalButton = new JButton(" Environmental Info ");
        buttonIdMap.put(environmentalButton, environmentalKey);
        environmentalButton.addActionListener(new AttrButtonClickListener());
        JLabel environmentalButtonLabel = new JLabel();

        JButton waterDepthButton = new JButton(" Water depth Info ");
        buttonIdMap.put(waterDepthButton, waterDepthKey);
        waterDepthButton.addActionListener(new AttrButtonClickListener());
        JLabel waterDepthButton4Label = new JLabel();

        JButton resetButton = new JButton();
        resetButton.setText(" Reset Cells ");
        resetButton.addActionListener(new ResetClickListener());
        JLabel resetButtonLabel = new JLabel();

        controlPanel.add(selectedButtonLabel);
        controlPanel.add(dummyLabel);

        controlPanel.add(magneticButton);
        //controlPanel.add(magneticButtonLabel);

        controlPanel.add(gravimetricButton);
        //controlPanel.add(gravimetricButtonLabel);

        controlPanel.add(environmentalButton);
        //controlPanel.add(environmentalButtonLabel);

        controlPanel.add(waterDepthButton);
        //controlPanel.add(waterDepthButton4Label);

        labelGridButton = new JButton();
        labelGridButton.setText(" Re-Order Grid ");
        labelInput = new JTextField(10);
        labelInput.setMaximumSize(new Dimension(100, 20));

        controlPanel.add(labelInput);
        controlPanel.add(labelGridButton);
        labelGridButton.addActionListener(new LabelClickListener());

        controlPanel.add(resetButton);
        controlPanel.add(resetButtonLabel);

        controlPanel.add(new JLabel("Instructions:"));

        JTextArea instructionTA = new JTextArea(INSTRUCTION_TXT);
        instructionTA.setEditable(false);
        instructionTA.setForeground(Color.RED);

        controlPanel.add(instructionTA);

        mainPanel.add(scrollPane);
        mainPanel.add(controlPanel);

    }

    private void initBoard() {
        /*
         * I created my user interface on the main panel, Constructed the LifeCell widgets then added them to the panel.
         * LifeCell widgets are stored in a two - dimensional array with identifier name [board]. 
         */
        gridPanel.removeAll();
        gridPanel.setBackground(Color.white);         // Background of my JPanel set to "white" using the setBackground method

        AtomicInteger cellNum = new AtomicInteger(startNumber);
        for (int u = 0; u < rowCount; u++) { // Identifier u is local to the outer for-loop 
            for (int r = 0; r < columnCount; r++) { // While the identifier r is local to this inner for-loop
                board[u][r].setCellNumber(cellNum.getAndIncrement());
                gridPanel.add(board[u][r]);
                gridPanel.setVisible(true);
            } // Inner for identifer r - loop comes to an end

        }  // Outer for identifer u - loop comes to an end

    }

    @Override
    public Container getPanel() {
        return mainPanel;
    }

    public void saveToFile(File selectedFile) {
        Properties p = new Properties();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                GridCell gridCell = board[i][j];
                p.put(String.format("(%s,%s)", i, j), gridCell.toString());
            }
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(selectedFile);
            p.store(out, "hello prop!!");
            System.out.println(String.format("Saved to %s", selectedFile.getAbsolutePath()));
        } catch (Exception ex) {
            Logger.getLogger(Grid.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(Grid.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    public void loadFromFile(File selectedFile) {
        FileInputStream in = null;
        try {
            in = new FileInputStream(selectedFile);
            Properties p = new Properties();
            p.load(in);
            GridCell[][] newBoard = new GridCell[rowCount][columnCount];
            for (Map.Entry<Object, Object> prp : p.entrySet()) {
                String key = (String) prp.getKey(), value = (String) prp.getValue();
                if (key.startsWith("(") & key.endsWith(")")) {
                    String[] parts = key.substring(1, key.length() - 1).split(",");
                    int row = Integer.parseInt(parts[0]);
                    int col = Integer.parseInt(parts[1]);
                    System.out.println("Adding cell: " + row + ", " + col);
                    newBoard[row][col] = GridCell.fromString(value);

                }
            }
            board = newBoard;
            rePaint();

        } catch (Exception ex) {
            Logger.getLogger(Grid.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(Grid.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    private class AttrButtonClickListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            Integer buttonId = buttonIdMap.get(e.getSource());
            selectedButtonLabel.setText(" Insert " + ((JButton) e.getSource()).getText() + " Readings ");
            selectedLegend = buttonId;
        }
    }

    private class LabelClickListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            startNumber = Integer.parseInt(labelInput.getText());
            rePaint();
        }
    }

    private class ResetClickListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            board = new GridCell[rowCount][columnCount];
            startNumber = Integer.parseInt((JOptionPane.showInputDialog("Insert Starting Grid Number from Simulation", "Input Text Here")));
            
            int s = startNumber;
            for (int i = 0; i < board.length; i++) {
                for (int j = 0; j < board[i].length; j++) {
                    board[i][j] = new GridCell(board, i, j, s);
                    s++;
                }
            }
        
            Grid.this.initBoard();
            rePaint();
        }
    }

    private void rePaint() {
        initBoard();
        mainPanel.repaint();
        mainPanel.validate();
    }

    public static void main(String[] args) {
        new Grid().showFrame();
    }

}
